.NET6 C#, LineBot, Line Messaging API, C#, dotnet core
Hihi 大家好,上一篇我們建立了 line bot 的 webhook url 連線,這一篇將會介紹 Line 提供的 webhook events 並建立接收對應行為~。
今天文章的內容,主要參考的來源當然是 官方文件,考量文章的長度,這邊就以常見的幾種事件(event)來做說明,如果各位發現有其它需求,一樣也可以從官方文件找到相關的資訊及範例。
建立 Dtos/Webhook 資料夾並新增類別 WebhookEventsDto.cs
並且宣告新的 class WebhookEventDto 然後將文件中的 common property 加入至class裏面,如 Type, Mode, TimeStamp 等等。後續就可以用物件裏面的屬性來直接對應到使用者輸入的資料(參數)。(*為了方便大家閱讀及一次呈現,這裏將其它常見的其它屬性也一併納入 如 SourceDto, DeliverycontextDto 類別等)
namespace LineBotMessage.Dtos
{
public class WebhookEventDto
{
// -------- 以下 common property --------
public string Type { get; set; } // 事件類型
public string Mode { get; set; } // Channel state : active | standby
public long Timestamp { get; set; } // 事件發生時間 : event occurred time in milliseconds
public SourceDto Source { get; set; } // 事件來源 : user | group chat | multi-person chat
public string WebhookEventId { get; set; } // webhook event id - ULID format
public DeliverycontextDto DeliveryContext { get; set; } // 是否為重新傳送之事件 DeliveryContext.IsRedelivery : true | false
}
// -------- 以下 common property --------
public class SourceDto
{
public string Type { get; set; }
public string? UserId { get; set; }
public string? GroupId { get; set; }
public string? RoomId { get; set; }
}
public class DeliverycontextDto
{
public bool IsRedelivery { get; set; }
}
}
因此我們這邊才會定義出 WebhookRequestBodyDto 類別,並在的宣告使用 Destination 字串,以及 WebhookEventDto的串列(List)。
這裏的對應(Mapping)觀念很重要!!!! 很重要!!! 很重要!!! 關係著要看懂官方文件裏的JSON範例,以及理解 C# 是如何將JSON結構 對應 成物件結構。
程式碼如下,方便參考
namespace LineBotMessage.Dtos
{
public class WebhookRequestBodyDto
{
public string? Destination { get; set; }
public List<WebhookEventDto> Events { get; set; }
}
}
目前,新增的資料夾及檔案 如下圖,
使用者向 Line Bot 傳送以下 7 種訊息時會產生 Message Event ,Line 再透過上一篇建立好的 webhook url 將其傳送到伺服器。
Message event 文件內容,需要宣告的屬性有 ReplyToken & Message,而 Message 分成 7 種 object,我們來一個一個帶過並宣告
不過建議搭配官方文件 一起服用,在對其定義格式了解後 再跟著我一起宣告
下圖是收到 Text message 時 Line 會傳送過來的 json 格式,文字訊息的內容包含了文字、emoji、還有 Line 在群組中的 Tag 訊息。
在 WebhookEventsDto.cs 內宣告以下幾個新的 Class 。
public class MessageEventDto
{
public string Id { get; set; }
public string Type { get; set; }
// Text Message Event
public string? Text { get; set; }
public List<TextMessageEventEmojiDto>? Emojis { get; set; }
public TextMessageEventMentionDto? Mention { get; set; }
}
public class TextMessageEventEmojiDto
{
public int Index { get; set; }
public int Length { get; set; }
public string ProductId { get; set; }
public string EmojiId { get; set; }
}
public class TextMessageEventEmojiDto
{
public int Index { get; set; }
public int Length { get; set; }
public string ProductId { get; set; }
public string EmojiId { get; set; }
}
public class TextMessageEventMentionDto
{
public List<TextMessageEventMentioneeDto> Mentionees { get; set; }
}
public class TextMessageEventMentioneeDto
{
public int Index { get; set; }
public int Length { get; set; }
public string UserId { get; set; }
}
public string? ReplyToken { get; set; } // 回覆此事件所使用的 token
public MessageEventDto? Message { get; set; } // 收到訊息的事件,可收到 text、sticker、image、file、video、audio、location 訊息
Image Message Event Json 格式,一起宣告前也記得詳讀官方文件
在 WebhookEventsDto.cs 下宣告以下幾個新的 Class。
public class ContentProviderDto
{
public string Type { get; set; }
public string? OriginalContentUrl { get; set; }
public string? PreviewImageUrl { get; set; }
}
public class ImageMessageEventImageSetDto
{
public string Id { get; set; }
public string Index { get; set; }
public string Total { get; set; }
}
public ContentProviderDto? ContentProvider { get; set; }
public ImageMessageEventImageSetDto? ImageSet { get; set; }
Video Message Event Json 格式,一起宣告前也記得詳讀官方文件
觀察過後可以發現,Video 與剛宣告完的 Image 比對後只多了 duration 的屬性,其中 ContentProvider 格式都一樣,所以我們只需要在 MessageEventDto 中新宣告 Duration 變數即可。
public int? Duration { get; set; } // 影片 or 音檔時長(單位:豪秒)
File 只需要多宣告兩個屬性即可 !
在 MessageEventDto 中宣告新變數
//File Message Event
public string? FileName { get; set; }
public int? FileSize { get; set; }
Location 也不用宣吿 Class,只需要宣告 4 個變數。
在 MessageEventDto 中宣告新變數
//Location Message Event
public string? Title { get; set; }
public string? Address { get; set; }
public double? Latitude { get; set; }
public double? Longitude { get; set; }
Sticker 也不用宣告新 Class,只需要宣告 4 個變數因為其中一個 Text 變數跟 Text message event 共用到了。
在 MessageEventDto 中宣告新變數
//Location Message Event
public string? Title { get; set; }
public string? Address { get; set; }
public double? Latitude { get; set; }
public double? Longitude { get; set; }
當機器人與使用者在同一個聊天室而使用者收回了他先前傳送的訊息,則Unsend event 會被觸發。
新增以下 class 放進 WebhookEventsDto.cs 中。
public class UnsendEventObjectDto
{
public string messageId { get; set; }
}
public UnsendEventDto? Unsend { get; set; } //使用者“收回”訊息事件
}
namespace LineBotMessage.Dtos
{
public class WebhookEventDto
{
// -------- 以下 common property --------
public string Type { get; set; } // 事件類型
public string Mode { get; set; } // Channel state : active | standby
public long Timestamp { get; set; } // 事件發生時間 : event occurred time in milliseconds
public SourceDto Source { get; set; } // 事件來源 : user | group chat | multi-person chat
public string WebhookEventId { get; set; } // webhook event id - ULID format
public DeliverycontextDto DeliveryContext { get; set; } // 是否為重新傳送之事件 DeliveryContext.IsRedelivery : true | false
// -------- 以下 event properties--------
public string? ReplyToken { get; set; } // 回覆此事件所使用的 token
public MessageEventDto? Message { get; set; } // 收到訊息的事件,可收到 text、sticker、image、file、video、audio、location 訊息
public UnsendEventDto? Unsend { get; set; } //使用者“收回”訊息事件
}
// -------- 以下 common property --------
public class SourceDto
{
public string Type { get; set; }
public string? UserId { get; set; }
public string? GroupId { get; set; }
public string? RoomId { get; set; }
}
public class DeliverycontextDto
{
public bool IsRedelivery { get; set; }
}
// -------- 以下 message event --------
public class MessageEventDto
{
public string Id { get; set; }
public string Type { get; set; }
// Text Message Event
public string? Text { get; set; }
public List<TextMessageEventEmojiDto>? Emojis { get; set; }
public TextMessageEventMentionDto? Mention { get; set; }
// Image & Video & Audio Message Event
public ContentProviderDto? ContentProvider { get; set; }
public ImageMessageEventImageSetDto? ImageSet { get; set; }
public int? Duration { get; set; }
//File Message Event
public string? FileName { get; set; }
public int? FileSize { get; set; }
//Location Message Event
public string? Title { get; set; }
public string? Address { get; set; }
public double? Latitude { get; set; }
public double? Longitude { get; set; }
// Sticker Message Event
public string? PackageId { get; set; }
public string? StickerId { get; set; }
public string? StickerResourceType { get; set; }
public List<string>? Keywords { get; set; }
}
public class TextMessageEventEmojiDto
{
public int Index { get; set; }
public int Length { get; set; }
public string ProductId { get; set; }
public string EmojiId { get; set; }
}
public class TextMessageEventMentionDto
{
public List<TextMessageEventMentioneeDto> Mentionees { get; set; }
}
public class TextMessageEventMentioneeDto
{
public int Index { get; set; }
public int Length { get; set; }
public string UserId { get; set; }
}
public class ContentProviderDto
{
public string Type { get; set; }
public string? OriginalContentUrl { get; set; }
public string? PreviewImageUrl { get; set; }
}
public class ImageMessageEventImageSetDto
{
public string Id { get; set; }
public string Index { get; set; }
public string Total { get; set; }
}
// -------- 以下 unsend event --------
public class UnsendEventDto
{
public string messageId { get; set; }
}
}
本篇要介紹的 events 都建好了,那我們就添加一個 LineBotService.cs 並寫出一個可以 handle 不同 event 接受時的事件吧。
建立 Enum 資料夾並新增 WebhookEventTypeEnum.cs
因為 C# 的 Enum 不能直接使用 string 作值,所以使用 class 代替其功能。
namespace LineBotMessage.Enum
{
public static class WebhookEventTypeEnum
{
public const string Message = "message";
public const string Unsend = "unsend";
public const string Follow = "follow";
public const string Unfollow = "unfollow";
public const string Join = "join" ;
public const string Leave = "leave";
}
}
using System;
using LineBotMessage.Dtos;
using LineBotMessage.Enum;
namespace LineBotMessage.Services
{
public class LineBotService
{
// (將 LineBotController 裡宣告的 ChannelAccessToken & ChannelSecret 移到 LineBotService中)
// 貼上 messaging api channel 中的 accessToken & secret
private readonly string channelAccessToken = "Your Channel Access Token";
private readonly string channelSecret = "Your Channel Secret";
public LineBotService()
{
}
public void ReceiveWebhook(WebhookRequestBodyDto requestBody)
{
foreach(var eventObject in requestBody.Events)
{
switch (eventObject.Type)
{
case WebhookEventTypeEnum.Message:
Console.WriteLine("收到使用者傳送訊息!");
break;
case WebhookEventTypeEnum.Unsend:
Console.WriteLine($"使用者{eventObject.Source.UserId}在聊天室收回訊息!");
break;
case WebhookEventTypeEnum.Follow:
Console.WriteLine($"使用者{eventObject.Source.UserId}將我們新增為好友!");
break;
case WebhookEventTypeEnum.Unfollow:
Console.WriteLine($"使用者{eventObject.Source.UserId}封鎖了我們!");
break;
case WebhookEventTypeEnum.Join:
Console.WriteLine("我們被邀請進入聊天室了!");
break;
case WebhookEventTypeEnum.Leave:
Console.WriteLine("我們被聊天室踢出了");
break;
}
}
}
}
}
using LineBotMessage.Dtos;
using LineBotMessage.Domain;
using Microsoft.AspNetCore.Mvc;
namespace LineBotMessage.Controllers
{
[Route("api/[Controller]")]
[ApiController]
public class LineBotController : ControllerBase
{
// 宣告 service
private readonly LineBotService _lineBotService;
// constructor
public LineBotController()
{
_lineBotService = new LineBotService();
}
[HttpPost("Webhook")]
public IActionResult Webhook(WebhookRequestBodyDto body)
{
_lineBotService.ReceiveWebhook(body); // 呼叫 Service
return Ok();
}
}
}
都改好後就可以使用自己的Line與機器人互動,測試看看接收功能是否正常,當然也可以透過 ngrok -> http://127.0.0.1:4040/ 的位置去查看收到的各種封包內容,有錯誤時也可以在這邊查找問題~
今天介紹了 6 種的 webhook events , 下一篇再介紹一部份事件後就會進入訊息推播的內容了~下一篇見
如果想要參考今天範例程式碼的部份,下面是 Git Repo 連結,方便大家參考。